package org.gnomus.server;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import org.gnomus.data.*;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static org.gnomus.util.strings.isEmpty;

public class Context {

    private static final ThreadLocal<Context> tl = new ThreadLocal<Context>();
    public static final UserService us = UserServiceFactory.getUserService();

    public final HttpServlet srv;
    public final HttpServletRequest req;
    public final HttpServletResponse res;
    public final String host;
    public final String uri;
    public final String anchor;
    public final String method;
    public final String query;
    public final Map<String, String> params;
    public final String b;
    public final String ip;
    public final String ua;
    public final String lcua;
    public final Boolean ie; // internet exploder
    public final Boolean cf; // chrome frame
    public final Cookie cookie;
    public User user;
    public Boolean admin;
    public account acnt;
    public Boolean ajax;
    public String view;
    public Map<String, Object> data;
    public Map<String, Object> errors;

    public final Boolean dev;

    public List<String> css = new ArrayList<String>();
    public List<String> js = new ArrayList<String>();

    public String[] common_css = { "gnomus" };
    public String[] util_js = { "context", "util/shapes", "util/atoms" };
    // , "molecule", "util/game", "util/shapes", "util/buttons",
    //         , "util/drag", "util/color", "util/image", "util/click" };

    private Context(HttpServlet servlet, HttpServletRequest req, HttpServletResponse res, String uri) {
        this.uri = uri;
        this.anchor = uri.contains("#") ? uri.substring(uri.indexOf("#")) : "";
        this.req = req;
        this.res = res;
        this.srv = servlet;
        this.host = req.getHeader("host");
        this.method = req.getMethod();
        this.query = req.getQueryString();
        this.params = getParams();
        this.b = this.params.get("b");
        this.ip = getIP();
        String ua = req.getHeader("User-Agent");
        this.ua = ua != null ? ua : C.APPENGINE_UA;
        String lcua = this.ua.toLowerCase();
        this.lcua = lcua;
        this.ajax = false;
        this.ie = lcua.contains("msie");
        this.cf = lcua.contains("chromeframe");
        this.cookie = new Cookie(this);
        this.user = us.getCurrentUser();
        this.admin = us.isUserLoggedIn() && us.isUserAdmin();
        this.acnt = this.user == null ? null : getAccount(this.user);
        this.data = new HashMap<String, Object>();
        this.errors = new HashMap<String, Object>();
        this.js.add("jquery");
        this.js.add("main");
        Collections.addAll(this.js, util_js);
        Collections.addAll(this.css, common_css);
        this.dev = !host.contains("gnomus-org.appspot.com");
    }

    public static Context get() {
        return tl.get();
    }

    public static Context create(HttpServlet servlet, HttpServletRequest req, HttpServletResponse res, String uri) {
        Context ctx = new Context(servlet, req, res, uri);
        tl.set(ctx);
        return ctx;
    }

    private Map<String, String> getParams() {
        Set keys = req.getParameterMap().keySet();
        Map<String, String> lcps = new HashMap<String, String>(keys.size() * 2);
        for (Object o : keys) {
            if (o instanceof String) {
                String key = (String) o;
                lcps.put(key.toLowerCase(), req.getParameter(key));
            }
        }
        return lcps;
    }

    private String getIP() {
        String ip = req.getHeader("X-Forwarded-for");
        if (!isEmpty(ip)) {
            int ix = ip.indexOf(',');
            if (ix > 0) {
                ip = ip.substring(0, ix);
            }
            return ip;
        } else {
            return req.getRemoteAddr();
        }
    }

    public void redirect(String uri) {
        if (uri != null) {
            try {
                res.addCookie(Context.get().cookie.getCookie());
                res.sendRedirect(uri);
            } catch (Throwable t) {
                throw new Error(t);
            }
        }
    }

    public account getAccount(User u) {
        Map<String, Object> filters = new HashMap<String, Object>();
        filters.put("auth_domain", u.getAuthDomain());
        filters.put("user_id", u.getUserId());
        Iterator<Entity> ie = store.get("account", filters).iterator();
        if (ie.hasNext()) {
            return new account(ie.next());
        } else {
            account acnt = new account(u.getAuthDomain(), u.getUserId());
            acnt.save();
            return acnt;
        }
    }

    public String toString() {
        StringBuilder s = new StringBuilder(1024);
        s.append("Context{\n\t").
                append("uri=").append(uri).append("\n\t").
                append("query=").append(query).append("\n\t").
                append("anchor=").append(anchor).append("\n\t").
                append("method=").append(method).append("\n\t").
                append("view=").append(view).append("\n\t").
                append("ip=").append(ip).append("\n\t").
                append("ua=").append(ua).append("\n\t").
                append("cookie=").append(cookie).append("\n\t").
        append("}");
        return s.toString();
    }
}
